import imaplib
import email
import os
from email.header import decode_header
from datetime import datetime, timedelta
import re
import requests
from email.utils import parsedate_to_datetime
import zipfile
import shutil
import json
import uuid

import pyzipper

from unzip import unzip_and_parseJson

# 邮箱配置
IMAP_SERVER = 'imap.qq.com'
EMAIL_ACCOUNT = '326367964@qq.com'  # 替换为你的QQ邮箱地址
EMAIL_PASSWORD = 'dqdolohvesckbgcj'  # 替换为你的授权码
deCodeNum = '453411'

def connect_to_mailbox():
    """连接到邮箱"""
    mail = imaplib.IMAP4_SSL(IMAP_SERVER)
    mail.login(EMAIL_ACCOUNT, EMAIL_PASSWORD)
    return mail

def rename_extracted_files(extract_path):
    """重命名解压后的文件夹和文件"""
    print('extract_path = ', extract_path)
    try:
        # 获取解压后的文件夹（应该只有一个）
        folders = [f for f in os.listdir(extract_path) if os.path.isdir(os.path.join(extract_path, f))]
        print('folders = ', folders)

        print('111')
        if not folders:
            print("未找到解压后的文件夹")
            return False
            
        old_folder = folders[0]

        # 去掉后缀"——【解压密码可在微信支付公众号查看】"
        new_subFolderName = old_folder.split('——')[0]
        old_folder_path = os.path.join(extract_path, old_folder)
        new_folder_path = os.path.join(extract_path, new_subFolderName)
        
        # 重命名文件夹
        os.rename(old_folder_path, new_folder_path)
        print(f"文件夹已重命名: {new_subFolderName}")
        
        # 重命名文件
        files = os.listdir(new_folder_path)
        for file in files:
            if file.endswith('.csv'):
                old_file_path = os.path.join(new_folder_path, file)
                new_file_name = f"{new_subFolderName}.csv"
                new_file_path = os.path.join(new_folder_path, new_file_name)
                os.rename(old_file_path, new_file_path)
                print(f"文件已重命名: {new_file_name}")
                return new_subFolderName
        
        return True
    except Exception as e:
        print(f"重命名文件时出错: {str(e)}")
        return False

def read_wechat_bill_csv(file_path):
    """
    Read WeChat bill data from a CSV file and return it as a string.
    
    Args:
        file_path (str): Path to the CSV file containing WeChat bill data
        
    Returns:
        str: Raw bill data as a string
    """
    try:
        with open(file_path, 'r', encoding='utf-8') as file:
            return file.read()
    except FileNotFoundError:
        raise FileNotFoundError(f"CSV file not found at: {file_path}")
    except Exception as e:
        raise Exception(f"Error reading CSV file: {str(e)}")

def parse_wechat_bill(raw_data):
    lines = raw_data.split("\n")
    bill_details = []
    header_info = {
        "totalTransactionNum": 0,
        "inputTransaction": {
            "transaction": 0,
            "totalInput": 0.0,
        },
        "outputTransaction": {
            "transaction": 0,
            "totalOutput": 0.0,
        },
        "neutralTransaction": {
            "transaction": 0,
            "totalNeutral": 0.0,
        }
    }
    
    # 状态标志位，用于跳过非明细数据
    in_detail_section = False
    
    for line in lines:
        line = line.strip()
        
        # 提取总记录数
        if line.startswith("共"):
            total_num_str = line.split("共")[1].split("笔记录")[0]
            header_info["totalTransactionNum"] = int(total_num_str)
        
        # 提取收入信息
        elif line.startswith("收入："):
            income_parts = line.split("收入：")[1].split("笔")
            header_info["inputTransaction"]["transaction"] = int(income_parts[0])
            header_info["inputTransaction"]["totalInput"] = float(income_parts[1].strip().split("元")[0])
        
        # 提取支出信息
        elif line.startswith("支出："):
            expense_parts = line.split("支出：")[1].split("笔")
            header_info["outputTransaction"]["transaction"] = int(expense_parts[0])
            header_info["outputTransaction"]["totalOutput"] = float(expense_parts[1].strip().split("元")[0])
        
        # 提取中性交易信息
        elif line.startswith("中性交易："):
            neutral_parts = line.split("中性交易：")[1].split("笔")
            header_info["neutralTransaction"]["transaction"] = int(neutral_parts[0])
            header_info["neutralTransaction"]["totalNeutral"] = float(neutral_parts[1].strip().split("元")[0])
        
        # 检查是否进入账单明细列表部分
        elif "微信支付账单明细列表" in line:
            in_detail_section = True
            continue
        
        # 解析账单明细
        if in_detail_section:
            if line.startswith("交易时间"):
                headers = line.split(",")
                continue
            
            if len(line.strip()) == 0 or not line.startswith("20"):  # 跳过空行或非明细数据
                continue
                
            fields = line.split(",", len(headers) - 1)
            detail = {}
            for i, field in enumerate(fields):
                key = headers[i].strip()
                value = field.strip().replace("¥", "")  # 移除金额前的符号
                if key in ["交易时间"]:
                    detail[key] = datetime.strptime(value, "%Y-%m-%d %H:%M:%S").isoformat()
                elif key in ["金额(元)"]:
                    detail[key] = float(value)
                else:
                    detail[key] = value
            
            bill_details.append(detail)

    # 构建最终 JSON 数据
    result = {
        **header_info,
        "bill_details": bill_details
    }

    return json.dumps(result, ensure_ascii=False, indent=2)


def extract_zip(zip_path, extract_path, password):
    """解压zip文件"""
    try:
        with zipfile.ZipFile(zip_path) as zf:
            zf.extractall(
                path=extract_path, 
                pwd=str(password).encode('utf-8')
            )
        print(f"文件已成功解压到: {extract_path}")
        
        # 重命名解压后的文件夹和文件
        new_subFolderName = rename_extracted_files(extract_path)
        print("new_subFolderName :", new_subFolderName)

        csv_file_path = f'./files/extracted/{new_subFolderName}/{new_subFolderName}.csv'
        raw_data = read_wechat_bill_csv(csv_file_path)
        json_data = parse_wechat_bill(raw_data)
        # print(json_data)

        return True


        # if success:
        #     print("文件重命名完成")
        #     # 解析CSV文件
        #     csv_file = find_csv_file(extract_path)
        #     if csv_file:
        #         json_data = parse_csv_to_json(csv_file)
        #         if json_data:
        #             # 使用相同的目录路径保存JSON文件
        #             json_file = os.path.join(
        #                 os.path.dirname(csv_file),
        #                 os.path.basename(csv_file).replace('.csv', '.json')
        #             )
        #             with open(json_file, 'w', encoding='utf-8') as f:
        #                 f.write(json_data)
        #             print(f"JSON文件已保存到: {json_file}")
        #             return True
        #     return False
        # else:
        #     print("文件重命名失败")
        #     return False
    except Exception as e:
        print(f"解压文件时出错: {str(e)}")
        return False

def find_csv_file(extract_path):
    """查找解压后的CSV文件"""
    for root, dirs, files in os.walk(extract_path):
        for file in files:
            if file.endswith('.csv'):
                return os.path.join(root, file)
    return None

def parse_csv_to_json(csv_file):
    """解析CSV文件并转换为JSON"""
    try:
        with open(csv_file, 'r', encoding='utf-8') as f:
            raw_data = f.read()
            
        lines = raw_data.split("\n")
        bill_details = []
        header_info = {
            "totalTransactionNum": 0,
            "inputTransaction": {
                "transaction": 0,
                "totalInput": 0.0,
            },
            "outputTransaction": {
                "transaction": 0,
                "totalOutput": 0.0,
            },
            "neutralTransaction": {
                "transaction": 0,
                "totalNeutral": 0.0,
            }
        }
        
        # 状态标志位，用于跳过非明细数据
        in_detail_section = False
        
        for line in lines:
            line = line.strip()
            
            # 提取总记录数
            if line.startswith("共"):
                total_num_str = line.split("共")[1].split("笔记录")[0]
                header_info["totalTransactionNum"] = int(total_num_str)
            
            # 提取收入信息
            elif line.startswith("收入："):
                income_parts = line.split("收入：")[1].split("笔")
                header_info["inputTransaction"]["transaction"] = int(income_parts[0])
                header_info["inputTransaction"]["totalInput"] = float(income_parts[1].strip().split("元")[0])
            
            # 提取支出信息
            elif line.startswith("支出："):
                expense_parts = line.split("支出：")[1].split("笔")
                header_info["outputTransaction"]["transaction"] = int(expense_parts[0])
                header_info["outputTransaction"]["totalOutput"] = float(expense_parts[1].strip().split("元")[0])
            
            # 提取中性交易信息
            elif line.startswith("中性交易："):
                neutral_parts = line.split("中性交易：")[1].split("笔")
                header_info["neutralTransaction"]["transaction"] = int(neutral_parts[0])
                header_info["neutralTransaction"]["totalNeutral"] = float(neutral_parts[1].strip().split("元")[0])
            
            # 检查是否进入账单明细列表部分
            elif "微信支付账单明细列表" in line:
                in_detail_section = True
                continue
            
            # 解析账单明细
            if in_detail_section:
                if line.startswith("交易时间"):
                    headers = line.split(",")
                    continue
                
                if len(line.strip()) == 0 or not line.startswith("20"):  # 跳过空行或非明细数据
                    continue
                    
                fields = line.split(",", len(headers) - 1)
                if len(fields) >= len(headers):  # 确保字段数量匹配
                    detail = {}
                    for i, field in enumerate(fields):
                        key = headers[i].strip()
                        value = field.strip().replace("¥", "")  # 移除金额前的符号
                        if key in ["交易时间"]:
                            detail[key] = datetime.strptime(value, "%Y-%m-%d %H:%M:%S").isoformat()
                        elif key in ["金额(元)"]:
                            detail[key] = float(value)
                        else:
                            detail[key] = value
                    
                    bill_details.append(detail)

        # 构建最终 JSON 数据
        result = {
            **header_info,
            "bill_details": bill_details
        }

        return json.dumps(result, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"解析CSV文件时出错: {str(e)}")
        return None

def is_valid_zip(file_path):
    """检查文件是否为有效的zip文件"""
    try:
        with zipfile.ZipFile(file_path) as zf:
            return True
    except zipfile.BadZipFile:
        return False

def decode_html_content(content):
    """解码HTML内容"""
    try:
        # 如果是bytes类型，先解码为字符串
        if isinstance(content, bytes):
            content = content.decode('utf-8')
        # 移除HTML标签和script标签
        content = re.sub(r'<[^>]+>', '', content)
        # 移除alert()
        content = re.sub(r'alert\([\'"](.+?)[\'"]\)', r'\1', content)
        return content.strip()
    except Exception as e:
        print(f"解码内容时出错: {str(e)}")
        return None

def fetch_emails(mail):
    """获取收件箱中的邮件"""
    # 选择收件箱
    mail.select('inbox')

    # 获取最近1天的邮件
    date = (datetime.now() - timedelta(days=1)).strftime("%d-%b-%Y")
    status, messages = mail.search(None, f'SINCE {date}')
    if status != 'OK':
        print("无法获取邮件")
        return

    # 获取邮件 ID 列表
    email_ids = messages[0].split()
    matching_emails = []

    # 遍历并过滤邮件
    for email_id in email_ids:
        status, msg_data = mail.fetch(email_id, '(RFC822)')
        if status != 'OK':
            continue

        for response_part in msg_data:
            if isinstance(response_part, tuple):
                msg = email.message_from_bytes(response_part[1])
                # 解析主题
                try:
                    subject_parts = decode_header(msg['Subject'])
                    subject = ''
                    for part, charset in subject_parts:
                        if isinstance(part, bytes):
                            try:
                                if charset:
                                    subject += part.decode(charset)
                                else:
                                    subject += part.decode('utf-8', errors='ignore')
                            except (LookupError, UnicodeDecodeError):
                                try:
                                    subject += part.decode('gbk', errors='ignore')
                                except:
                                    subject += part.decode('utf-8', errors='ignore')
                        else:
                            subject += str(part)
                except:
                    subject = "无法解码的主题"
                
                if "微信支付-账单流水文件" in subject:
                    # 获取邮件日期
                    date_str = msg.get('Date')
                    if date_str:
                        email_date = parsedate_to_datetime(date_str)
                        matching_emails.append((email_id, email_date))

    if not matching_emails:
        print("未找到符合条件的邮件")
        return

    # 按时间排序并获取最新的邮件
    latest_email = sorted(matching_emails, key=lambda x: x[1], reverse=True)[0]
    email_id = latest_email[0]
    
    # 处理最新的邮件
    status, msg_data = mail.fetch(email_id, '(RFC822)')
    if status != 'OK':
        print("无法获取邮件内容")
        return

    # 确保下载目录存在
    if not os.path.exists('./files'):
        os.makedirs('./files')

    # 解析邮件内容
    for response_part in msg_data:
        if isinstance(response_part, tuple):
            msg = email.message_from_bytes(response_part[1])
            print(f"处理最新邮件 (发送时间: {latest_email[1]})")

            # 如果邮件有多个部分
            if msg.is_multipart():
                for part in msg.walk():
                    content_type = part.get_content_type()
                    if content_type == "text/html":
                        # 解析HTML内容中的下载链接
                        html_content = part.get_payload(decode=True).decode()
                        # 查找下载链接
                        download_links = re.findall(r'href=[\'"]?([^\'" >]+)', html_content)
                        for link in download_links:
                            if "download" in link.lower():
                                try:
                                    print(f"正在下载文件: {link}")
                                    headers = {
                                        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
                                    }
                                    response = requests.get(link, headers=headers, allow_redirects=True)
                                    
                                    if response.status_code == 200:
                                        content_type = response.headers.get('Content-Type', '')
                                        print(f"响应Content-Type: {content_type}")
                                        
                                        # 如果返回的是HTML，可能包含错误信息
                                        if 'text/html' in content_type.lower():
                                            error_message = decode_html_content(response.content)
                                            print(f"服务器返回错误信息: {error_message}")
                                            print("下载链接可能已过期，请在微信中重新申请导出账单")
                                            return False
                                        
                                        # 生成文件名
                                        current_date = datetime.now().strftime("%Y%m%d")
                                        # 生成独特的编码（UUID 的前 8 位）
                                        unique_code = uuid.uuid4().hex[:8]
                                        # 构造文件名
                                        filename = f"weixin_bill_{current_date}_{unique_code}.zip"

                                        filepath = os.path.join('./files', filename)

                                        
                                        # 保存文件
                                        with open(filepath, 'wb') as f:
                                            f.write(response.content)
                                        print(f"文件已保存到: {filepath}")
                                        
                                        # 验证文件是否为有效的zip文件
                                        if not is_valid_zip(filepath):
                                            print(f"下载的文件不是有效的zip文件")
                                            # 打印文件的前100个字节，用于调试
                                            with open(filepath, 'rb') as f:
                                                content = f.read(100)
                                                print(f"文件内容预览: {content}")
                                            return False
                                except Exception as e:
                                    print(f"下载或解压文件时出错: {str(e)}")
                                    # 如果文件存在但处理失败，打印文件信息
                                    if os.path.exists(filepath):
                                        print(f"文件大小: {os.path.getsize(filepath)} 字节")
                                        with open(filepath, 'rb') as f:
                                            content = f.read(100)
                                            print(f"文件内容预览: {content}")
    print(f"文件已保存到: {filepath}")
    return filepath


def get_json_data(deCodeNum: str):
    """主函数"""
    # 邮箱配置
    # deCodeNum = '017952'

    try:
        mail = connect_to_mailbox()
        csvFilePath = fetch_emails(mail)

        print('csvFilePath = ', csvFilePath)
        print('deCodeNum = ', deCodeNum)

        json_data = unzip_and_parseJson(csvFilePath, deCodeNum)
        return json_data

    except Exception as e:
        print(f"发生错误: {str(e)}")
    finally:
        mail.logout()

def main():
    """主函数"""
    # 邮箱配置
    # deCodeNum = '017952'

    try:
        mail = connect_to_mailbox()
        csvFilePath = fetch_emails(mail)

        print('csvFilePath = ', csvFilePath)
        print('deCodeNum = ', deCodeNum)

        unzip_and_parseJson(csvFilePath, deCodeNum)

        # extract_zip('./files/weixin_bill_20250326.zip', './files/extracted/', '544071')

    except Exception as e:
        print(f"发生错误: {str(e)}")
    finally:
        mail.logout()

if __name__ == '__main__':
    main()